package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
public class AuthGlobalFilter implements GlobalFilter {
    //路径匹配判断
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${authUrls.url}")
    private String antUrlsUrl;

    //网关用户登录鉴权
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //获取请求路径
        String path = request.getURI().getPath();
        //若是内部接口，则返回 权限不允许
        if (antPathMatcher.match("/**/inner/**", path)){
            ServerHttpResponse response = exchange.getResponse();
            return out(response,ResultCodeEnum.PERMISSION);
        }
        //从request中获取userId
        String userId = getUserId(request);
        //获取临时用户id
        String userTempId = this.getUserTempId(request);
        //若用户id返回-1，表明ip不匹配，cookie盗取
        if ("-1".equals(userId)){
            ServerHttpResponse response = exchange.getResponse();
            return out(response,ResultCodeEnum.PERMISSION);
        }
        //若请求路径 符合配置文件中指定的，判断是否登录,若未登录，跳转登录页面
        String[] split = antUrlsUrl.split(",");
        for (String url : split) {
            if (path.indexOf(url) != -1 && StringUtils.isEmpty(userId)){
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                return response.setComplete();
            }
        }
        //若请求路径 为 /api/**/auth/** 切未登录，直接返回未登录，无权限
        if (antPathMatcher.match("/api/**/auth/**",path)){
            if (StringUtils.isEmpty(userId)){
                ServerHttpResponse response = exchange.getResponse();
                return out(response,ResultCodeEnum.PERMISSION);
            }
        }
        //若请求路径 符合配置文件中指定的，判断是否登录,若已经登录，则将userId放入request的Header中，继续向下走
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)){
            if (!StringUtils.isEmpty(userId)){
                request.mutate().header("userId",userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)){
                request.mutate().header("userTempId",userTempId).build();
            }
            //filter方法需要ServerWebExchange
            return chain.filter(exchange.mutate().request(request).build());
        }
        //若不需要登录权限，直接向下进行
        return chain.filter(exchange);
    }

    //获取用户id
    private String getUserId(ServerHttpRequest request) {
        String token = "";
        //先从头信息里取token
        List<String> stringList = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(stringList)){
            token = stringList.get(0);
        }else {
            //若头信息中token信息，无数据，则从cookie中取
            HttpCookie httpCookie = request.getCookies().getFirst("token");
            if (httpCookie != null){
                token = httpCookie.getValue();
            }
        }
        String userKey = "user:login:"+token;
        String jsonStr = (String) redisTemplate.opsForValue().get(userKey);
        //若从redis中获取的id ip 数据为空，则返回空
        if (StringUtils.isEmpty(jsonStr)){
            return "";
        }
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String userId = (String) jsonObject.get("id");
        String ip = (String) jsonObject.get("ip");
        String currentIp = IpUtil.getGatwayIpAddress(request);
        //若ip不匹配，则返回-1
        if (!currentIp.equals(ip)){
            return "-1";
        }
        return userId;
    }

    //获取临时用户id
    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = "";
        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if (httpCookie != null){
            userTempId = httpCookie.getValue();
        }else {
            List<String> stringList = request.getHeaders().get("userTempId");
            if (!CollectionUtils.isEmpty(stringList)){
                userTempId = stringList.get(0);
            }
        }
        return userTempId;
    }

    //无权时返回响应
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //将无权的状态码，及 描述信息封装如result中的code及message中
        Result<Object> result = Result.build(null, resultCodeEnum);
        String strJson = JSON.toJSONString(result);
        //字节缓冲流
        DataBuffer wrap = response.bufferFactory().wrap(strJson.getBytes());
        //设置浏览器解析的编码（解码）方式
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        //将信息写到相应，展示到页面，返回
        return response.writeWith(Mono.just(wrap));
    }
}
